package com.batata.continuing.utils;

import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * redis 行级锁的实现
 */
@Component
public class RedisRowLockUtil {


    @Autowired
    private RedisUtil redisUtil;


    /**
     * key 前置内容
     * 完整应为 前置 + table + id
     */
    private final String ROW_LOCK_KEY = "row:lock:";

    /**
     * key 分隔符
     */
    private final String KEY_SEPARATOR = ":";

    /**
     * redis 默认值
     */
    private final String REDIS_VALUE_DEFAULT = "locking";

    /**
     * 默认过期时间
     */
    private final Long REDIS_TIME_OUT_DEFAULT = 10L;

    /**
     * 最大尝试次数
     */
    private final int TRY_COUNT_MAX = 3;


    private String getRowLockKey(String table, String rowId) {
        return ROW_LOCK_KEY + table + KEY_SEPARATOR + rowId;
    }


    /**
     * 获取锁状态，若没有则并设置
     *
     * @param table  表面
     * @param rowId  行标识
     * @param whoGet 请求人标识，何以为uuid
     * @return true 没锁并设置成功 false 有锁或设置失败
     */
    public boolean getLockStatusAndSetLockStatus(String table, String rowId, String whoGet) {

        String rowLockKey = getRowLockKey(table, rowId);

        String nowValue = REDIS_VALUE_DEFAULT + whoGet;
        return redisUtil.setIfAbsent(rowLockKey, nowValue, REDIS_TIME_OUT_DEFAULT);

    }

    /**
     * 获取锁状态，并尝试默认次数
     *
     * @param table  表面
     * @param rowId  行标识
     * @param whoGet 请求人标识，何以为uuid
     * @return true 没锁并设置成功 false 有锁或设置失败
     */
    public boolean getLockStatusAndTry(String table, String rowId, String whoGet) {
        boolean lockStatusAndSetLockStatus = getLockStatusAndSetLockStatus(table, rowId, whoGet);

        if (lockStatusAndSetLockStatus) {
            return true;
        }

        for (int i = 0; i < TRY_COUNT_MAX; i++) {
            if (getLockStatusAndSetLockStatus(table, rowId, whoGet)) {
                return true;
            } else {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    System.out.println("等待异常！");
                    return false;
                }
            }
        }

        return false;
    }

    /**
     * 释放锁
     *
     * @param table  表面
     * @param rowId  行标识
     * @param whoGet 请求人标识，何以为uuid
     */
    public void releaseLockStatus(String table, String rowId, String whoGet) {
        String rowLockKey = getRowLockKey(table, rowId);
        String nowLockValue = redisUtil.get(rowLockKey);
        String needValue = REDIS_VALUE_DEFAULT + whoGet;
        if (!StrUtil.isEmpty(nowLockValue) && nowLockValue.equals(needValue)) {
            redisUtil.releaseLock(rowLockKey, nowLockValue);
        }
    }


}
